/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mylist;

import exceptions.MyIndexOutOfBoundsException;
import interfaces.MyList;
import java.util.Arrays;
import java.util.RandomAccess;

/**
 *
 * @author Daryna_Ragimova
 */
public class MyArrayList<E> implements MyList<E>, RandomAccess{
    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer.
     */
    private transient Object[] elements;

    /**
     * The size of the ArrayList (the number of elements it contains).
     */
    private int size;

    public MyArrayList() {
        this(10);
    }
    
    public MyArrayList(MyList c) {
        elements = c.toArray();
	size = elements.length;
    }
    
    public MyArrayList(int initialCapacity){
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
	this.elements = new Object[initialCapacity];
    }
    
    @Override
    public void add(E e) {
        elements[size] = e;
        size++;
    }
    //add element on (index + 1) position
    @Override
    public void add(int index, E element)  {
        if (index >= size || index < 0)
	    throw new MyIndexOutOfBoundsException("The index is not right");
        System.arraycopy(elements, index, elements, index + 1, size - index);
	elements[index] = element;
	size++;
    }

    @Override
    public void addAll(E[] c) {
        System.arraycopy(c, 0, elements, size + 1, c.length);
        size += c.length;
    }
    // add after element with such index all elements from array
    @Override
    public void addAll(int index, E[] array)  {
         if (index >= size || index < 0)
	    throw new MyIndexOutOfBoundsException("The index is not right");
         int quantityOfElems = array.length;
         System.arraycopy(elements, index, elements, index + quantityOfElems, size - index);
         System.arraycopy(array, 0, elements, index + 1, array.length);
         size += array.length;
    }

    @Override
    public E get(int index)  {
        if (index >= size || index < 0)
	    throw new MyIndexOutOfBoundsException("The index is not right");
        return (E)elements[index];
    }

    @Override
    public E remove(int index)  {
        if (index >= size || index < 0)
	    throw new MyIndexOutOfBoundsException("The index is not right");
        E elemForRemoving = (E)elements[index];
        int quantityOfElemsToMove = size - index - 1;
        if (quantityOfElemsToMove > 0){
            System.arraycopy(elements, index+1, elements, index, quantityOfElemsToMove);
        }
        size--;
        elements[size] = null;
        return elemForRemoving;
    }

    @Override
    public void clear() {
        for (int i = 0; i < size; i++)
	    elements[i] = null;
	size = 0;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public void set(int index, E e)  {
        if (index > size || index < 0)
	    throw new MyIndexOutOfBoundsException("The index is not right");
        elements[index] = e;
    }

    @Override
    public int indexOf(Object o) {
        if (o == null) {
	    for (int i = 0; i < size; i++)
		if (elements[i]==null)
		    return i;
	} else {
	    for (int i = 0; i < size; i++)
		if (o.equals(elements[i]))
		    return i;
	}
	return -1;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public Object[] toArray() {
        return Arrays.copyOf(elements, size);
    }
    
    @Override
    public MyArrayListIterator<E> iterator() {
        return new MyArrayListIterator(0);
    }
    @Override
    public MyArrayListIterator<E> iterator(int index) {
        return new MyArrayListIterator(index);
    }
    
      
    public void ensureCapacity(int minCapacity){
        if (elements.length < minCapacity){
            elements = Arrays.copyOf(elements, minCapacity);
        }
    }
    public void trimToSize(){
        if (elements.length != size){
             elements = Arrays.copyOf(elements, size);
        }
    }
    
    class MyArrayListIterator<E> implements MyListIterator<E>{

        public MyArrayListIterator(int index) {
            this.index = index;
        }
        
        
        private int index;
        private E lastReturned = null;
        
        
        @Override
        public boolean hasNext() {
            return index < size - 1;
        }

        @Override
        public E next() {
            if (index < size - 1){
                index++;
                lastReturned = (E)elements[index];
                return lastReturned;
            }
            return null;
        }

        @Override
        public void remove() {
        if (index < size)
        {
            int quantityOfElemsToMove = size - index - 1;
            if (quantityOfElemsToMove > 0){
                System.arraycopy(elements, index+1, elements, index, quantityOfElemsToMove);
            }
            size--;
            elements[size] = null;
            index = 0;
            }
        }

        @Override
        public boolean hasPrevious() {
            return index > 0;
        }

        @Override
        public E previous() {
            if (index >= 0){
                index--;
                lastReturned = (E)elements[index];
                return lastReturned;
            }
            return null;
        }

        @Override
        public int nextIndex() {
            if (index < size){
                return index + 1;
            }
            else return -1;
        }

        @Override
        public void set(E e) {
            elements[index] = e;
        }

        @Override
        public void add(E e) {
            elements[size] = e;
            size++;
        }
        
    }
}
